package org.example.service.handler;

import com.example.common.Ticker;
import com.example.user.StockTradeRequest;
import com.example.user.StockTradeResponse;
import org.example.exceptions.InsufficientBalanceException;
import org.example.exceptions.InsufficientSharesException;
import org.example.exceptions.UnknownTickerException;
import org.example.exceptions.UnknownUserException;
import org.example.repository.PortfolioItemRepository;
import org.example.repository.UserRepository;
import org.example.util.EntityMessageMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class StockTradeRequestHandler {
    private final UserRepository userRepository;
    private final PortfolioItemRepository portfolioItemRepository;

    public StockTradeRequestHandler(UserRepository userRepository, PortfolioItemRepository portfolioItemRepository) {
        this.userRepository = userRepository;
        this.portfolioItemRepository = portfolioItemRepository;
    }

    /**
     * 用户购买股票请求
     * @param request  请求
     * @return  相应
     */
    @Transactional
    public StockTradeResponse buyStock(StockTradeRequest request) {
        //如果是购买的是未知的股票 抛出异常
        this.validateTicker(request.getTicker());
        var user = this.userRepository.findById(request.getUserId())
                .orElseThrow(() -> new UnknownUserException(request.getUserId()));
        var totalPrice = request.getQuantity() * request.getPrice();
        //验证下用户余额释放足够 不够抛出异常
        this.validateUserBalance(user.getId(), user.getBalance(), totalPrice);

        // 扣减用户余额
        user.setBalance(user.getBalance() - totalPrice);
        this.portfolioItemRepository.findByUserIdAndTicker(user.getId(), request.getTicker())
                .ifPresentOrElse(
                        //存在就更新
                        item -> item.setQuantity(item.getQuantity() + request.getQuantity()),
                        //不存在就插入
                        () -> this.portfolioItemRepository.save(EntityMessageMapper.toPortfolioItem(request))
                );
        return EntityMessageMapper.toStockTradeResponse(request, user.getBalance());
    }

    /**
     * 抛售股票
     * @param request  请求
     * @return
     */
    @Transactional
    public StockTradeResponse sellStock(StockTradeRequest request) {
        // 如果是购买的是未知的股票 抛出异常
        this.validateTicker(request.getTicker());
        //获取用户
        var user = this.userRepository.findById(request.getUserId())
                .orElseThrow(() -> new UnknownUserException(request.getUserId()));

        var portfolioItem = this.portfolioItemRepository.findByUserIdAndTicker(user.getId(), request.getTicker())
                //数量大于或者等于请求数量才能抛售成功
                .filter(pi -> pi.getQuantity() >= request.getQuantity())
                //如果为空抛出异常
                .orElseThrow(() -> new InsufficientSharesException(user.getId()));

        // valid request
        var totalPrice = request.getQuantity() * request.getPrice();
        user.setBalance(user.getBalance() + totalPrice);
        portfolioItem.setQuantity(portfolioItem.getQuantity() - request.getQuantity());
        return EntityMessageMapper.toStockTradeResponse(request, user.getBalance());
    }


    /**
     * 如果是购买的是未知的股票 抛出异常
     * @param ticker  股票类型
     */
    private void validateTicker(Ticker ticker) {
        if (Ticker.UNKNOWN.equals(ticker)) {
            throw new UnknownTickerException();
        }
    }

    private void validateUserBalance(Integer userId, Integer userBalance, Integer totalPrice) {
        if (totalPrice > userBalance) {
            throw new InsufficientBalanceException(userId);
        }
    }
}
